﻿using MahApps.Metro.Controls;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using System.Xml.Linq;

namespace ImageGallery
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : MetroWindow
    {
        public Task myAsyncTask;
        private List<string> mSupportedExtensions;
        private string currentFolderPath = string.Empty;
        private int currentPage = 0;
        private int totalPages;
        public bool isSinglePhoto = false;
        private string currentFullScreenPhoto = string.Empty;
        private string currentlocalPhoto = string.Empty;
        private string currentlocalPhoto1 = string.Empty;
        private DispatcherTimer slider = new DispatcherTimer();

        public ObservableCollection<ImageClass> Images
        {
            get { return (ObservableCollection<ImageClass>)GetValue(ImagesProperty); }
            set { SetValue(ImagesProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Images.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ImagesProperty =
            DependencyProperty.Register("Images", typeof(ObservableCollection<ImageClass>), typeof(MainWindow), new PropertyMetadata(null));

        public MainWindow()
        {
            InitializeComponent();
            myAsyncTask = Task.Factory.StartNew(() => VoiceSynthesis.Speak(getModule(), 0, "Welcome to Perceptual Gallery."));

            this.WindowState = System.Windows.WindowState.Maximized;
            this.WindowStyle = System.Windows.WindowStyle.None;
            this.ShowTitleBar = false;

            Images = new ObservableCollection<ImageClass>();
            mSupportedExtensions = new List<string>() { ".bmp", ".jpg", ".gif", ".jpe", ".jpeg", ".jfif", ".tif", ".tiff" };
            this.DataContext = this;

            System.Threading.Thread thread = new System.Threading.Thread(DoRecognition);
            thread.Start();
            thread.IsBackground = true;
            System.Threading.Thread.Sleep(50);
            LoadBookmarks(0);
        }

        public string getModule()
        {
            PXCMSession session = null;

            try
            {
                var status = PXCMSession.CreateInstance(out session);

                if (status == pxcmStatus.PXCM_STATUS_NO_ERROR)
                    return string.Empty;

                PXCMSession.ImplDesc desc = new PXCMSession.ImplDesc();
                desc.cuids[0] = PXCMVoiceSynthesis.CUID;

                PXCMSession.ImplDesc desc1;
                if (session.QueryImpl(ref desc, 0, out desc1) < pxcmStatus.PXCM_STATUS_NO_ERROR)
                    return string.Empty;

                return desc1.friendlyName.get();
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                session.Dispose();
            }
        }

        delegate void DoRecognitionCompleted();
        private void DoRecognition()
        {
            GestureRecognition gr = new GestureRecognition(this);
            gr.SimplePipeline();
        }

        public void LoadImages(string pathLocation, bool deepSearch, int pageNumber)
        {
            bool runOnce = true;

            Images.Clear();

            if (pathLocation == string.Empty)
            {
                LoadBookmarks(pageNumber);
                return;
            }

            SearchOption opt = SearchOption.TopDirectoryOnly;
            if (deepSearch)
                opt = SearchOption.AllDirectories;

            var totalPhotos = new DirectoryInfo(pathLocation).GetFiles("*", SearchOption.AllDirectories).Where(s => mSupportedExtensions.Contains(s.Extension.ToLower())).Count();
            totalPages = totalPhotos / 21 + (totalPhotos % 21 != 0 ? 1 : 0);

            foreach (var file in new DirectoryInfo(pathLocation).GetFiles("*", opt).Where(s => mSupportedExtensions.Contains(s.Extension.ToLower())).OrderBy(s => s.Name).Skip(pageNumber * 21).Take(21))
            {
                if (runOnce)
                {
                    runOnce = false;
                    currentFullScreenPhoto = file.FullName;
                }

                AddImage(file.FullName);
            }
        }

        public void LoadImages(List<string> imagesLocation)
        {
            Images.Clear();

            foreach (var item in imagesLocation)
            {
                if (File.Exists(item))
                {
                    AddImage(item);
                }
            }
        }

        public void LoadBookmarks(int pageNumber)
        {
            try
            {
                currentFolderPath = string.Empty;
                folderPath.Content = "Select Folder";
                bool isFirstImage = true;

                List<string> imagelist = new List<string>();
                XDocument xdoc = XDocument.Load("bookmark.xml");
                var descendents = xdoc.Element("Gallery").Element("Bookmarks").Descendants("Image");

                var totalPhotos = descendents.Count();
                totalPages = totalPhotos / 21 + (totalPhotos % 21 != 0 ? 1 : 0);

                foreach (var item in descendents.Skip(pageNumber * 21).Take(21))
                {
                    if (isFirstImage)
                    {
                        currentFullScreenPhoto = item.Value;
                        isFirstImage = false;
                    }

                    imagelist.Add(item.Value);
                }

                showImageMatrix();
                LoadImages(imagelist);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        public void AddImage(string location)
        {
            FileInfo file = new FileInfo(location);
            if (IsImage(file.Extension))
            {
                ImageClass newImg = new ImageClass(location);
                Images.Add(newImg);
            }
        }

        private bool IsImage(string extension)
        {
            if (mSupportedExtensions.Contains(extension.ToLower())) return true;
            return false;
        }

        public void togglePhotoDisplay()
        {
            if (isSinglePhoto)
            {
                showImageMatrix();
            }
            else
            {
                showSinglePhoto();
            }
        }

        public void showImageMatrix()
        {
            isSinglePhoto = false;
            mainImage.Visibility = System.Windows.Visibility.Collapsed;
            imageList.Visibility = System.Windows.Visibility.Visible;
            folderPicker.Visibility = System.Windows.Visibility.Visible;
            bookmarkImage.Visibility = System.Windows.Visibility.Collapsed;
        }

        public void showSinglePhoto()
        {
            isSinglePhoto = true;

            BitmapImage bmp = new BitmapImage();
            bmp.BeginInit();
            bmp.UriSource = new Uri(currentFullScreenPhoto);
            bmp.EndInit();

            TransformedBitmap tb = new TransformedBitmap();
            tb.BeginInit();
            tb.Source = bmp;

            RotateTransform rotate = new RotateTransform(0);
            tb.Transform = rotate;
            tb.EndInit();

            mainImage.Source = tb;
            mainImage.ToolTip = currentFullScreenPhoto;

            mainImage.Visibility = System.Windows.Visibility.Visible;
            imageList.Visibility = System.Windows.Visibility.Collapsed;
            folderPicker.Visibility = System.Windows.Visibility.Collapsed;
            mainGrid.RowDefinitions[0].Height = GridLength.Auto;
            showBookMarkIcon();
            bookmarkImage.Visibility = System.Windows.Visibility.Visible;
        }

        private void chooseFolder_Click_1(object sender, RoutedEventArgs e)
        {
            currentPage = 0;
            var dialog = new System.Windows.Forms.FolderBrowserDialog();

            System.Windows.Forms.DialogResult result = dialog.ShowDialog();
            if (result == System.Windows.Forms.DialogResult.OK)
            {
                currentFolderPath = dialog.SelectedPath;
                folderPath.Content = dialog.SelectedPath;

                DirectoryInfo dinfo = new DirectoryInfo(currentFolderPath);
                var totalPhotos = dinfo.GetFiles("*", SearchOption.AllDirectories).Where(s => mSupportedExtensions.Contains(s.Extension.ToLower())).Count();
                totalPages = totalPhotos / 21 + (totalPhotos % 21 != 0 ? 1 : 0);

                LoadImages(currentFolderPath, true, currentPage);
                SaveCurrentPathInXML();
            }
        }

        private void SaveCurrentPathInXML()
        {
            XDocument xdoc = XDocument.Load("bookmark.xml");

            try
            {
                var imagePaths = xdoc.Element("Gallery").Element("Paths").Elements("ImagePath");
                var result = imagePaths.Where(s => s.Value == currentFolderPath);

                if (result.Count() == 0)
                {
                    XElement xe = new XElement("ImagePath", folderPath.Content);
                    XAttribute xa = new XAttribute("Index", imagePaths.Count() + 1);
                    xe.Add(xa);

                    xdoc.Element("Gallery").Element("Paths").Add(xe);
                    xdoc.Save("bookmark.xml");
                }
            }
            catch (Exception)
            { }
        }

        public void SetNextFolderPath(int direction)
        {
            XDocument xdoc = XDocument.Load("bookmark.xml");
            XElement nextElement = null;
            try
            {
                var result = xdoc.Element("Gallery").Element("Paths").Elements("ImagePath").Where(s => s.Value == currentFolderPath).FirstOrDefault();
                if (result != null)
                {
                    string index = (Convert.ToInt16(result.Attribute("Index").Value) + direction).ToString();
                    nextElement = xdoc.Element("Gallery").Element("Paths").Descendants().Where(s => s.Attribute("Index").Value == index).FirstOrDefault();
                }
                else
                {
                    nextElement = xdoc.Element("Gallery").Element("Paths").Descendants().Where(s => s.Attribute("Index").Value == "1").FirstOrDefault();
                }

                if (nextElement != null)
                {
                    currentFolderPath = nextElement.Value;
                    folderPath.Content = currentFolderPath;
                    LoadImages(currentFolderPath, true, 0);
                }
                else
                {
                    myAsyncTask = Task.Factory.StartNew(() => VoiceSynthesis.Speak(getModule(), 0, "There is no more history."));
                }
            }
            catch (Exception)
            { }
        }

        public void PreviousPhoto()
        {
            if (isSinglePhoto)
            {
                var fileinf = Images.Where(s => s.Label == currentFullScreenPhoto).SingleOrDefault();

                var currentitem = Images.IndexOf(fileinf);

                if (currentitem > 0)
                {
                    showSingleImage(--currentitem);
                    return;
                }
            }

            currentPage -= 1;
            if (currentPage < 0)
            {
                currentPage = 0;
                myAsyncTask = Task.Factory.StartNew(() => VoiceSynthesis.Speak(getModule(), 0, "There are no more Photos before this."));
            }

            LoadImages(currentFolderPath, true, currentPage);
        }

        public void NextPhotos()
        {
            if (isSinglePhoto)
            {
                var fileinf = Images.Where(s => s.Label == currentFullScreenPhoto).SingleOrDefault();

                var currentitem = Images.IndexOf(fileinf);

                if (Images.Count() > currentitem + 1)
                {
                    showSingleImage(++currentitem);
                    return;
                }
            }

            currentPage += 1;
            if (currentPage >= totalPages)
            {
                currentPage = totalPages - 1;

                if (isSinglePhoto)
                {
                    myAsyncTask = Task.Factory.StartNew(() => VoiceSynthesis.Speak(getModule(), 0, "Slideshow completed."));
                    showImageMatrix();
                    return;
                }

                myAsyncTask = Task.Factory.StartNew(() => VoiceSynthesis.Speak(getModule(), 0, "There are no more Photos after this."));
            }

            LoadImages(currentFolderPath, true, currentPage);
        }

        public void showSingleImage(int index)
        {
            try
            {
                var nextImagePath = Images[index].Label;

                currentFullScreenPhoto = nextImagePath;

                BitmapImage bmp = new BitmapImage();
                bmp.BeginInit();
                bmp.UriSource = new Uri(nextImagePath);
                bmp.EndInit();

                TransformedBitmap tb = new TransformedBitmap();
                tb.BeginInit();
                tb.Source = bmp;

                RotateTransform rotate = new RotateTransform(0);
                tb.Transform = rotate;
                tb.EndInit();

                mainImage.Source = tb;
                mainImage.ToolTip = nextImagePath;
                showBookMarkIcon();
                bookmarkImage.Visibility = System.Windows.Visibility.Visible;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        public void RotatePhoto()
        {
            var transformBitmap = (TransformedBitmap)mainImage.Source;
            RotateTransform rotateTransform = (RotateTransform)(transformBitmap.Transform);
            rotateTransform.Angle += 90;
            mainImage.Source = transformBitmap.Clone();
        }

        public void SaveToBookmark()
        {
            try
            {
                XDocument xdoc = XDocument.Load("bookmark.xml");

                if (IsImageBookmarked(currentFullScreenPhoto))
                {
                    return;
                }

                myAsyncTask = Task.Factory.StartNew(() => VoiceSynthesis.Speak(getModule(), 0, "bookmarked."));
                XElement xe = new XElement("Image", currentFullScreenPhoto);
                xdoc.Element("Gallery").Element("Bookmarks").Add(xe);
                xdoc.Save("bookmark.xml");

                showBookMarkIcon();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        public void unSaveBookmark()
        {
            try
            {
                if (IsImageBookmarked(currentFullScreenPhoto))
                {
                    XDocument xdoc = XDocument.Load("bookmark.xml");
                    var nodeToDelete = xdoc.Element("Gallery").Element("Bookmarks").Elements("Image").Where(s => s.Value == currentFullScreenPhoto);

                    myAsyncTask = Task.Factory.StartNew(() => VoiceSynthesis.Speak(getModule(), 0, "unbookmarked."));

                    foreach (var e in nodeToDelete)
                    {
                        e.Remove();
                    }
                    xdoc.Save("bookmark.xml");
                }

                showBookMarkIcon();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        public void slideShow()
        {
            try
            {
                slider.Tick += slider_Elapsed;
                slider.Interval = new TimeSpan(0, 0, 2);

                slider.Start();

                myAsyncTask = Task.Factory.StartNew(() => VoiceSynthesis.Speak(getModule(), 0, "Slideshow started."));
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        void slider_Elapsed(object sender, EventArgs e)
        {
            if (!isSinglePhoto)
            {
                DispatcherTimer slider = (DispatcherTimer)sender;
                slider.Stop();
                return;
            }

            if (currentPage <= totalPages)
            {
                NextPhotos();
            }
        }

        private bool IsImageBookmarked(string imagePath)
        {
            XDocument xdoc = XDocument.Load("bookmark.xml");

            var result = xdoc.Element("Gallery").Element("Bookmarks").Elements().Where(s => s.Value == imagePath);

            if (result.Count() > 0)
            {
                return true;
            }

            return false;
        }

        private void showBookMarkIcon()
        {
            try
            {
                XDocument xdoc = XDocument.Load("bookmark.xml");
                var result = xdoc.Element("Gallery").Element("Bookmarks").Elements().Where(s => s.Value == currentFullScreenPhoto);

                if (result.Count() > 0)
                {
                    bookmarkImage.Source = new BitmapImage(new Uri("pack://application:,,,/bookmark.png"));
                }
                else
                {
                    bookmarkImage.Source = new BitmapImage(new Uri("pack://application:,,,/bookmark-gray.png"));
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }

    public class ImageClass
    {
        public TransformedBitmap ImageUri { get; private set; }

        public string Label { get; set; }

        public ImageClass(string location)
        {
            if (File.Exists(location))
            {
                BitmapImage bmp = new BitmapImage();
                bmp.BeginInit();
                bmp.UriSource = new Uri(location);
                bmp.DecodePixelHeight = 100;
                bmp.EndInit();

                RotateTransform rotate = new RotateTransform(0);
                TransformedBitmap tbmp = new TransformedBitmap();
                tbmp.BeginInit();
                tbmp.Source = bmp;
                tbmp.Transform = rotate;
                tbmp.EndInit();

                ImageUri = tbmp;

                Label = location;
            }
        }
    }
}
